/*
 * Created by Gibbs on 2021/1/1.
 * Copyright (c) 2021 Gibbs. All rights reserved.
 */

#include <base/Log.h>
#include <thread>
#include "FrameSource.h"
#include "Source.h"

#define TAG "FrameSource"

FrameSource::FrameSource(int audioMaxSize, int audioMixSize, int videoMaxSize, int videoMinSize) {
    LOGI(TAG, "CoreFlow : create FrameSource");
    audioFrameQueue = new ConcurrentQueue<MediaData*>(audioMaxSize, audioMixSize, "AudioFrameQueue");
    videoFrameQueue = new ConcurrentQueue<MediaData*>(videoMaxSize, videoMinSize, "VideoFrameQueue");
    this->audioMaxSize = audioMaxSize;
    this->audioMinSize = audioMixSize;
    this->videoMaxSize = videoMaxSize;
    this->videoMinSize = videoMinSize;
    isEof = false;
}

FrameSource::~FrameSource() {
    LOGI(TAG, "CoreFlow : FrameSource destroyed %d %d",
         audioFrameQueue->size(), videoFrameQueue->size());
    delete audioFrameQueue;
    audioFrameQueue = nullptr;
    delete videoFrameQueue;
    videoFrameQueue = nullptr;
}

unsigned long FrameSource::pushAudFrame(MediaData *frame) {
    LOGD(TAG, "pushAudFrame %lld", frame->pts);
    auto desBuffer = new MediaData(frame);
    unsigned long size = audioFrameQueue->push(desBuffer);
    if (isQueueQuit(size)) {
        return SOURCE_ERROR;
    } else if (size >= audioMaxSize) {
        return SOURCE_FULL;
    } else if (size > audioMinSize) {
        return SOURCE_RICH;
    } else if (size > 0) {
        return SOURCE_POOR;
    }
    return isEof ? SOURCE_ERROR : SOURCE_EMPTY;
}

unsigned long FrameSource::pushVidFrame(MediaData *frame) {
    LOGD(TAG, "pushVidFrame %lld", frame->pts);
    auto desBuffer = new MediaData(frame);
    unsigned long size = videoFrameQueue->push(desBuffer);
    if (isQueueQuit(size)) {
        return SOURCE_ERROR;
    } else if (size >= videoMaxSize) {
        return SOURCE_FULL;
    } else if (size > videoMinSize) {
        return SOURCE_RICH;
    } else if (size > 0) {
        return SOURCE_POOR;
    }
    return isEof ? SOURCE_ERROR : SOURCE_EMPTY;
}

unsigned long FrameSource::readAudFrame(MediaData **frame) {
    unsigned long size = audioFrameQueue->front(frame);
    if (isQueueQuit(size)) {
        return SOURCE_ERROR;
    } else if (size >= audioMaxSize) {
        LOGD(TAG, "readAudFrame %lld", (*frame)->pts);
        return SOURCE_FULL;
    } else if (size > audioMinSize) {
        LOGD(TAG, "readAudFrame %lld", (*frame)->pts);
        return SOURCE_RICH;
    } else if (size > 0) {
        return SOURCE_POOR;
    }
    return isEof ? SOURCE_END : SOURCE_EMPTY;
}

unsigned long FrameSource::readVidFrame(MediaData **frame) {
    unsigned long size = videoFrameQueue->front(frame);
    if (isQueueQuit(size)) {
        return SOURCE_ERROR;
    } else if (size >= videoMaxSize) {
        LOGD(TAG, "readVidFrame %lld", (*frame)->pts);
        return SOURCE_FULL;
    } else if (size > videoMinSize) {
        LOGD(TAG, "readVidFrame %lld", (*frame)->pts);
        return SOURCE_RICH;
    } else if (size > 0) {
        return SOURCE_POOR;
    }
    return isEof ? SOURCE_END : SOURCE_EMPTY;
}

void FrameSource::popAudFrame(MediaData *frame) {
    LOGD(TAG, "popAudFrame %lld", frame->pts);
    audioFrameQueue->pop();
}

void FrameSource::popVidFrame(MediaData *frame) {
    LOGD(TAG, "popVidFrame %lld", frame->pts);
    videoFrameQueue->pop();
}

void FrameSource::flush() {
    audioFrameQueue->flush();
    videoFrameQueue->flush();
    isEof = false;
    LOGI(TAG, "flushBuffer");
}

void FrameSource::quit() {
    LOGI(TAG, "quit");
    audioFrameQueue->quit();
    videoFrameQueue->quit();
}

unsigned long FrameSource::audioSize() {
    return audioFrameQueue->size();
}

unsigned long FrameSource::videoSize() {
    return videoFrameQueue->size();
}
